package common.correspondence;

import common.Port;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Client extends Thread{
    String name;
    Socket s;
    OutputStream output;
    PrintWriter printWriter;

    InetAddress srcIp;
    InetAddress dstIp;
    Port port;
    int srvPort;

    Thread th;
    BlockingQueue<Message> msgQueue;
    public static final byte[] MESSAGE_START_TAG = new byte[]{(byte) 0xF1, (byte) 0xE2, (byte) 0xD3, (byte) 0xC4};
//    public static final byte[] MESSAGE_END_TAG = new byte[]{(byte) 0x1F, (byte) 0x2E, (byte) 0x3D, (byte) 0x4C};

    public Client(InetAddress srcIp, InetAddress dstIp, int srvPort, Port port) {
        super();
        name = String.format("%s client", port.name);

        this.srcIp = srcIp;
        this.dstIp = dstIp;
        this.port = port;
        this.srvPort = srvPort;

        this.s = null;
        this.msgQueue = new LinkedBlockingQueue<>();
        this.start();
    }

    public void send(Message msg){
        try {
            msgQueue.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public boolean test(){
        if (s == null || output == null) return false;

        if(s.isClosed())
            return link();
//
//        if(printWriter.checkError()) {
//            return link();
//        }
        return true;
    }

    public void close(){
        try {
            if(this.s != null)
                this.s.close();
            th.interrupt();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean link() {
        try{
            if (s!=null){
//                printWriter.close();
                output.close();
                s.close();
            }
            this.s = new Socket(dstIp, srvPort, srcIp, 0);
            port.device.printf("%s 连接完成\n", name);
            output = s.getOutputStream();

//            printWriter = new PrintWriter(output);
            return true;
        }catch (IOException e){
            return false;
        }
    }
    public boolean isAlready(){
        return test();
    }

    public void run(){
        th = Thread.currentThread();
        th.setName(name);

        while(true){
            try {
                if(link()) break;
                //noinspection BusyWait
                sleep(2000);
            } catch (InterruptedException interruptedException) {
                interruptedException.printStackTrace();
            }
        }
        Message m;
        while (true){
            try {
//                System.out.println("send");
                m = msgQueue.take();
                if (!test()){
                    port.device.printf("%s连接发生错误, 无法发送信息:%s\n", name, m.msg);
                }
                if(m.message.getSerializedSize() == 0){
                    System.err.println("zero!!!");
                }
                int length = m.message.getSerializedSize();
                output.write(MESSAGE_START_TAG);
                output.write(intToBytes(m.type.ordinal()));
                output.write(intToBytes(length));
                m.message.writeTo(output);
//                output.write(m.dataBytes);
                output.flush();
            } catch (InterruptedException e) {
                break;
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    private static byte[] intToBytes(int a){
        byte[] b = new byte[4];
        b[0] = (byte)((a >> 24) & 0xFF);
        b[1] = (byte)((a >> 16) & 0xFF);
        b[2] = (byte)((a >>  8) & 0xFF);
        b[3] = (byte)((a      ) & 0xFF);
        return b;
    }

    private static byte[] zeroByte(int num){
        byte[] r = new byte[num];
        while (--num >= 0){
            r[num] = (byte) 0x00;
        }
        return r;
    }
}
